using System;
using System.Linq;
using Engine;
using Engine.Graphics;
using Engine.OldSerialization;
using Game;

namespace RuthlessConquest {
    public abstract class Player : Entity {
        public PlayerDescription Description;

        public Faction Faction => Description.Faction;

        public PlayerType Type => Description.Type;

        public string Name => Description.Name;

        public Guid Guid => Description.Guid;

        public Platform? Platform => Description.Platform;

        public int FactionProductionFactor { get; set; } = 100;

        public bool IsControllingPlayer => PlayersModule.ControllingPlayer == this;

        public FactionStatus Status => PlayersModule.GetFactionStatus(Faction);

        public double StatusChangeTime => PlayersModule.GetFactionStatusChangeTime(Faction);

        public bool AreSatellitesEnabled { get; set; } = true;

        public Player() { }

        public Player(PlayerDescription description) => Description = description;

        public override void Serialize(InputArchive archive) {
            archive.Serialize("Description", ref Description);
            FactionProductionFactor = archive.Serialize<int>("FactionProductionFactor");
            AreSatellitesEnabled = archive.Serialize<bool>("AreSatellitesEnabled");
        }

        public override void Serialize(OutputArchive archive) {
            archive.Serialize("Description", Description);
            archive.Serialize("FactionProductionFactor", FactionProductionFactor);
            archive.Serialize("AreSatellitesEnabled", AreSatellitesEnabled);
        }

        public virtual void Step() {
            int factionProductionPercentage = PlanetsModule.GetFactionProductionPercentage(Faction);
            FactionProductionFactor = MathUtils.Clamp(150 - factionProductionPercentage * 3 / 2, 50, 100);
        }

        public virtual void Update() { }

        public virtual void Draw(Color colorTransform) { }

        public static string GetPlayerTypeName(PlayerType playerType) {
            int index = playerType switch {
                PlayerType.Human => 1,
                PlayerType.NoviceAI => 2,
                PlayerType.EasyAI => 3,
                PlayerType.ModerateAI => 4,
                PlayerType.HardAI => 5,
                PlayerType.VeryHardAI => 6,
                PlayerType.BrutalAI => 7,
                _ => 0
            };
            string result = LanguageControl.Get("RCPlayerTypeName", index);
            return index == 0 ? throw new InvalidOperationException(result) : result;
        }

        public static Player CreatePlayer(PlayerDescription playerDescription) => playerDescription.Type switch {
            PlayerType.Human => new HumanPlayer(playerDescription),
            PlayerType.NoviceAI => new RandomAIPlayer(playerDescription, 0),
            PlayerType.EasyAI => new RandomAIPlayer(playerDescription, 1),
            PlayerType.ModerateAI => new RandomAIPlayer(playerDescription, 2),
            PlayerType.HardAI => new WiseAIPlayer(playerDescription, 0),
            PlayerType.VeryHardAI => new WiseAIPlayer(playerDescription, 1),
            PlayerType.BrutalAI => new WiseAIPlayer(playerDescription, 2),
            _ => throw new InvalidOperationException("Unknown player type.")
        };

        public static Color GetColor(Faction faction) {
            if (faction == Faction.None) {
                return Color.Gray;
            }
            return Planet.GetColor(faction);
        }

        public static Texture2D GetPlatformTexture(Platform? platform) {
            return platform switch {
                global::RuthlessConquest.Platform.Desktop => Textures.Gui.LaptopLogo,
                global::RuthlessConquest.Platform.Android => Textures.Gui.AndroidLogo,
                global::RuthlessConquest.Platform.Ios => Textures.Gui.AppleLogo,
                global::RuthlessConquest.Platform.Amazon => Textures.Gui.AmazonLogo,
                global::RuthlessConquest.Platform.Steam => Textures.Gui.SteamLogo,
                _ => null
            };
        }

        public override void OnAdded() {
            if (Faction == Faction.Neutral) {
                throw new InvalidOperationException();
            }
            PlayersModule playersModule = Game.PlayersModule;
            if (Faction == Faction.None) {
                playersModule.publicSpectators.Add(this);
                playersModule.publicSpectators = new DynamicArray<Player>(playersModule.publicSpectators.OrderBy(p => p.Guid.ToString()));
                //playersModule.publicSpectators.Sort((p1, p2) => p1.Guid.CompareTo(p2.Guid));
            }
            else {
                if (playersModule.publicPlayers.Any(p => p.Faction == Faction)) {
                    throw new InvalidOperationException();
                }
                playersModule.publicPlayers.Add(this);
                playersModule.publicPlayers = new DynamicArray<Player>(playersModule.publicPlayers.OrderBy(p => p.Guid.ToString()));
                //playersModule.publicPlayers.Sort((p1, p2) => p1.Guid.CompareTo(p2.Guid));
            }
            if (Guid == SettingsManager.PlayerGuid
                && this is HumanPlayer humanPlayer) {
                playersModule.ControllingPlayer = humanPlayer;
            }
        }

        public override void OnRemoved() {
            PlayersModule playersModule = Game.PlayersModule;
            playersModule.publicPlayers.Remove(this);
            playersModule.publicSpectators.Remove(this);
            if (this == playersModule.ControllingPlayer) {
                playersModule.ControllingPlayer = null;
            }
        }
    }
}